package net.p2pcdn.common;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.paypal.base.rest.APIContext;
import net.p2pcdn.http.PoolHttpClientService;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHeaders;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class PayPalAccessTokenProvider {
    private final static Logger _logger = LoggerFactory.getLogger(PayPalAccessTokenProvider.class);
    private final static String PRO_ACCESS_TOKEN_URL = "https://api.paypal.com/v1/oauth2/token";
    private final static String SANDBOX_ACCESS_TOKEN_URL = "https://api.sandbox.paypal.com/v1/oauth2/token";
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private APIContext apiContext;
    @Autowired
    private PoolHttpClientService poolHttpClientService;
    @Value("${paypal.mode}")
    private String mode;

    private final static String PAY_PAL_ACCESS_TOKEN = "pay_pal_access_token";

    public String getAccessToken() {
        BoundValueOperations<String, String> valueOperations = redisTemplate.boundValueOps(PAY_PAL_ACCESS_TOKEN);
        String redisToken = valueOperations.get();
        if(StringUtils.isNotBlank(redisToken)){
            return redisToken;
        }
        String token = apiContext.getClientID() + ":" + apiContext.getClientSecret();
        byte[] encodedAuth = Base64.encodeBase64(
                token.getBytes(StandardCharsets.UTF_8));
        Map<String, String> header = new HashMap<>();
        header.put("Accept", "application/json");
        header.put("Accept-Language", "en_US");
        header.put(HttpHeaders.AUTHORIZATION, "Basic " + new String(encodedAuth));
        Map<String, String> params = new HashMap<>();
        params.put("grant_type", "client_credentials");
        CloseableHttpResponse response = poolHttpClientService.post(mode.equalsIgnoreCase("SANDBOX") ? SANDBOX_ACCESS_TOKEN_URL : PRO_ACCESS_TOKEN_URL, params, header);
        try {
            String jsonResult = EntityUtils.toString(response.getEntity());
            JSONObject object = JSON.parseObject(jsonResult);
            String accessToken = object.getString("access_token");
            if (accessToken != null) {
                valueOperations.set(accessToken, 32000, TimeUnit.SECONDS);
                return accessToken;
            }
        } catch (IOException e) {
            _logger.error(e.getMessage(), e);
        }
        return null;
    }
}
